/* ************************************
*《精通Windows API》
* 示例代码
* Regions.c
* 13.8 区域的填充和反转
**************************************/
/* 头文件 */
#include <windows.h>
/* 全局变量 */
LPSTR szAppName = "RGN";//标题名
LPSTR szTitle = "RGN Sample";//类名
/* 函数声明 */
LRESULT CALLBACK WndProc( HWND ,  UINT ,  WPARAM ,  LPARAM );//处理主窗口的消息
//LRESULT:_W64 long   
//CALLBACK:__stdcall被这个关键字修饰的函数，其参数都是从右向左通过堆栈传递的(__fastcall的前面部分由ecx,edx传)，函数调用在返回前要由被调用者//清理堆栈。
//HDWN:窗口句柄   UINT:unsigned int   WPARAM;包含有关消息的附加信息,不同消息其值有所不同   LPARAM:用于提供消息的附加信息
/*************************************
* ElliRgns
* 功能	创建椭圆区域，并进行填充和反转
**************************************/
HRGN ElliRgns(HWND hwnd, POINT point)//HRGN:区域句柄，用于设置窗体区域的一个值   POINT：定义了屏幕上或窗口中的一个点的X和Y坐标
{
	// RECT 区域、画刷
	RECT rect, rectClient;//RECT：定义了一个矩形区域及其左上角和右下角的坐标
	HRGN hrgn;
	HBRUSH hBrushOld, hBrush;//HBRUSH:画刷句柄
	// DC
	HDC hdc = GetDC(hwnd);//HDC:设备环境句柄   GetDC():是GetDC的一个扩展，它能使应用程序更多地控制在客户区域内如何或是否发生剪切
	GetClientRect(hwnd,&rectClient);//把客户区的大小写进第二个参数所指的Rect结构当中,客户区坐标指定客户区的左上角和右下角
	// 点的周围一块区域
	rect.left = point.x - 40;
	rect.right = point.x + 40;
	rect.top = point.y - 30;
	rect.bottom = point.y + 30;
	// 通过RECT 创建椭圆区域
	hrgn = CreateEllipticRgnIndirect(&rect);//CreateEllipticRgnIndirect():创建一内切于特定矩形的椭圆区域
	// 创建画刷
	hBrush = CreateSolidBrush(RGB(0,255,0));//创建一个具有指定颜色的逻辑刷子,初始化一个指定颜色的画刷,画笔可以随后被选为任何设备上下文的                                                //当前刷子
	// 为DC 选择画刷
	hBrushOld = (HBRUSH)SelectObject(hdc,hBrush);//SelectObject():选择一对象到指定的设备上下文环境中，新对象替换先前的相同类型的对象
	// 使用当前画刷绘制区域
	PaintRgn(hdc,hrgn);
	// 等待一断时间后，将刚才绘制的区域进行反转
	Sleep(3000);
	InvertRgn(hdc,hrgn);
	// 释放资源
	hBrush = (HBRUSH)SelectObject(hdc,hBrushOld);
	DeleteObject(hBrush);
	DeleteObject(hrgn);
	DeleteDC( hdc );
	return 0;
}
//WINAPI:__stdcall   HINSTANCE:当前实例句柄   LPSTR:指向程序命令行参数的指针   nCmdShow:应用程序开始执行时显示窗口显示方式的整数标识
int WINAPI WinMain(
				   HINSTANCE hInstance,
				   HINSTANCE hPrevInstance,
				   LPSTR lpCmdLine,
				   int nCmdShow)
{
	MSG msg;//附加信息与具体
消息号的值有关，
在Win中消息用
结构体MSG表示
	HWND hWnd;
	WNDCLASS wc;//窗口类

	wc.style = CS_OWNDC; //保存设备内容
	wc.lpfnWndProc = (WNDPROC)WndProc; 
	wc.cbClsExtra = 0; //窗口类无扩展
	wc.cbWndExtra = 0; //窗口实例无扩展
	wc.hInstance = hInstance;
	wc.hIcon = NULL; //窗口无图标
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);//窗口采用箭头光标
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);//窗口背景色
	wc.lpszMenuName = NULL;//窗口中无菜单
	wc.lpszClassName = szAppName; //窗口类名为"RGN Sample"

	if (!RegisterClass(&wc))//RegisterClass():注册窗口类
	{
		return (FALSE);
	}

	hWnd = CreateWindow(
		szAppName, 
		szTitle, 
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, 
		NULL, 	NULL,	hInstance, NULL 
		);//创建窗口类   WS_OVERLAPPEDWINDOW:创建一带边框、标题栏、系统菜单及最大、最小化按钮的窗口
	//CW_USEDEFAULT:系统选择的默认位置窗口的左上角,而忽略了y参数
	if (!hWnd)
	{
		return (FALSE);
	}

	ShowWindow(hWnd, nCmdShow); //显示窗口
	UpdateWindow(hWnd); //绘制用户区

	while (GetMessage(&msg, NULL, 0, 0))//获取消息
	{
		TranslateMessage(&msg);//将虚拟键消息转化为字符消息,字符消息被寄送到调用线程的消息队列里
		DispatchMessage(&msg);//调度一个消息给窗口函数
	}

	return (int)(msg.wParam);

	UNREFERENCED_PARAMETER(lpCmdLine); ////展开传递的参数或表达式，避免编译器关于未引用参数的警告
}


LRESULT CALLBACK WndProc(
						 HWND hWnd, 
						 UINT message, 
						 WPARAM uParam, 
						 LPARAM lParam)
{

	switch (message)
	{
	case WM_CREATE://创建
		break;

	case WM_PAINT://绘制
		break;

	case WM_LBUTTONDOWN:
		{
			// 获得点击的位置，传递给ElliRgns
			POINT point;
			point.x = LOWORD(lParam);
			point.y = HIWORD(lParam);
			ElliRgns(hWnd, point);
		}
		break;

	case WM_DESTROY: 
		PostQuitMessage(0);//销毁指定的窗口
		break;

	default: 
		return (DefWindowProc(hWnd, message, uParam, lParam));//默认时默认采用系统消息默认处理函数
	}
	return (0);
}